
 #include "CPU_const.h"







void formAnswer(void);



bool findID(void);
uint readShort(void);
uint readLong(void);
void writeShort(uint data);

uint RegsToBytes(uint adr,uint nBytes);

uint dataRead(uint adr, uint n_bytes);
uint writeSinglReg(uint adr, uint data);
uint writeMultReg(uint adr, uint Nreg);
uint writeMaskReg(uint adr, uint mskAND, uint mskOR);








UARTbuf *pUx;
uint InBgn=0, InEnd=0, InID;
  char queryID, Cmnd;
  uint posa=IDseek, NofByte;


void ModBus(UARTbuf *pUART) { pUx = pUART; }





//void BufPointSet(char *pBi, char *pBo, uint size)
//{ pBufI = pBi; pBufO = pBo; buf_size = size; indxO = size; }
  
//void QueueInSet(xQueueHandle *pqiI, xQueueHandle *pqbI) {pqindxI = pqiI; pqbrdI = pqbI;}

//void QueueOutSet(xQueueHandle *pqiO, xQueueHandle *pqbOI) {pqindxO = pqiO; pqbrdOISR = pqbOI;}

//void MutexOutSet(xSemaphoreHandle *pxWBOe) {pxWBOen = pxWBOe;}




/****************************************************************************************************/
/*               Q U E R Y      C H E C K I N G     O F      I N P U T     D A T A                  */
/****************************************************************************************************/
void check_Query(void)
{ uint end;
//
  while(1)
   {
     if(InBgn==InEnd) (*pUx).RecieveIndI(&InEnd);
     switch(posa)
      { 
        case(IDseek):  if(findID()) {InID = InBgn; (*pUx).next(&InBgn);}
                     break;
        case(COMask):  Cmnd = (*pUx).RdBufIn(InBgn);
                       switch(Cmnd)
                        {
                          case(R_H_R):
                          case(P_S_R): posa = ENDwait; NofByte = 8; break;
                          case(M_W_R): posa = ENDwait; NofByte = 10; break;
                          case(P_M_R): posa = NoBwait; NofByte = 7; break;
                          default:     posa = IDseek;
                         }
                     break;
        case(COMansw): Cmnd = (*pUx).RdBufIn(InBgn);
                       switch(Cmnd)
                        {
                          case(P_M_R):
                          case(P_S_R): posa = ENDwait; NofByte = 8; break;
                          case(M_W_R): posa = ENDwait; NofByte = 10; break;
                          case(R_H_R): posa = NoBwait; NofByte = 3; break;
                          case(R_H_R|ERRmsk):
                          case(P_S_R|ERRmsk):
                          case(P_M_R|ERRmsk):
                          case(M_W_R|ERRmsk): posa = ENDwait; NofByte = 5; break;
                          default:     posa = IDseek;
                         }
                     break;
        case(NoBwait): if( (*pUx).CountBytes(InID,InEnd)<NofByte )
                         { (*pUx).RecieveIndI(&InEnd); }
                        else
                         {
                           if(Cmnd==P_M_R) NofByte = 9 + (*pUx).RdBufIn((*pUx).shift(InID,6));
                           if(Cmnd==R_H_R) NofByte = 5 + (*pUx).RdBufIn((*pUx).shift(InID,2));  
                           if( (*pUx).CheckSize(NofByte) ) {posa = ENDwait;} else {posa = IDseek;}
                          }
                     break;
        case(ENDwait): if( (*pUx).CountBytes(InID,InEnd)<NofByte )
                         { (*pUx).RecieveIndI(&InEnd); }
                        else
                         {
                           end = (*pUx).shift(InID,NofByte);
                           if( (*pUx).CRC16in(InID,end) )
                            {(*pUx).SendBrdI(InID); posa = QUERYok;}  else  {posa = IDseek;}
                          }
                     break;
       };/*switch(posa)*/

     if(posa==QUERYok)
      { 
        /*Rxd disable mutex ON*/
        /*function working with query*/
        /*Rxd disable mutex OFF ?????????????? may be not hear*/
        
        if(queryID==Dev_ID)
         { 
           formAnswer();
           //U0THR = Dev_ID;
         }
        else
         {  U0THR = PC_ID;}
        
        posa = IDseek;   InBgn = end; (*pUx).ResetBrdI();
      
       }/*if(posa==QUERYok)*/
                              
                              
                              
     
                              
    };/*while(1)*/
//
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/




/****************************************************************************************************/
/*                                    F O R M       A N S W E R                                     */
/****************************************************************************************************/
void formAnswer(void)
{ uint adr, n_regs, AnswBgn, error, mskOR;
//mutex catch;
  xSemaphoreTake((*pUx).mWrBufOen, portMAX_DELAY);
//address & number of registers form:
  adr = readShort();   n_regs = readShort();
//answer form:
  AnswBgn = (*pUx).GetBrdO();  (*pUx).WrBufOut(Dev_ID);
  switch(Cmnd)
   {
     case(R_H_R): n_regs = RegsToBytes(adr,n_regs<<1);/*transform number of regs to number of bytes*/
                  (*pUx).WrBufOut(Cmnd);   (*pUx).WrBufOut(n_regs);
                  error = dataRead(adr,n_regs);
               break;
     case(P_S_R): error = writeSinglReg(adr,n_regs);
               break;
     case(P_M_R): error = writeMultReg(adr,n_regs);
               break;       
     case(M_W_R): mskOR = readShort(); error = writeMaskReg(adr,n_regs,mskOR);
               break;
    }/*switch(Cmnd)*/
//check error:
  if(!error)
    { 
      (*pUx).WrBufOut(Cmnd); writeShort(adr); writeShort(n_regs);
      if(Cmnd==M_W_R) writeShort(mskOR);
     } 
   else
    { if(error!=No_ERR) {(*pUx).WrBufOut(Cmnd|0x80); (*pUx).WrBufOut(error);}; }
//CRC16 write:
  (*pUx).CRC16out(AnswBgn);
//start send:
  (*pUx).SetBrdOISR();  (*pUx).StartTransmite();   xSemaphoreGive((*pUx).mWrBufOen);
//
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/




/****************************************************************************************************/
/*                                    F O R M       A N S W E R                                     */
/****************************************************************************************************/
void formAsk(char cmnd)
{ uint adr, n_regs, AnswBgn, error, mskOR;
//mutex catch;
  xSemaphoreTake((*pUx).mWrBufOen, portMAX_DELAY);
//address & number of registers form:
  adr = readShort();   n_regs = readShort();
//answer form:
  AnswBgn = (*pUx).GetBrdO();  (*pUx).WrBufOut(Dev_ID);
  switch(Cmnd)
   {
     case(R_H_R): n_regs = RegsToBytes(adr,n_regs<<1);/*transform number of regs to number of bytes*/
                  (*pUx).WrBufOut(Cmnd);   (*pUx).WrBufOut(n_regs);
                  error = dataRead(adr,n_regs);
               break;
     case(P_S_R): error = writeSinglReg(adr,n_regs);
               break;
     case(P_M_R): error = writeMultReg(adr,n_regs);
               break;       
     case(M_W_R): mskOR = readShort(); error = writeMaskReg(adr,n_regs,mskOR);
               break;
    }/*switch(Cmnd)*/
//check error:
  if(!error)
    { 
      (*pUx).WrBufOut(Cmnd); writeShort(adr); writeShort(n_regs);
      if(Cmnd==M_W_R) writeShort(mskOR);
     } 
   else
    { if(error!=No_ERR) {(*pUx).WrBufOut(Cmnd|0x80); (*pUx).WrBufOut(error);}; }
//CRC16 write:
  (*pUx).CRC16out(AnswBgn);
//start send:
  (*pUx).SetBrdOISR();  (*pUx).StartTransmite();   xSemaphoreGive((*pUx).mWrBufOen);
//
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/








uint dataRead(uint adr, uint n_bytes)
{
  while(n_bytes) { (*pUx).WrBufOut(0x56+n_bytes); --n_bytes; }
  
  return No_ERR;
}








uint writeSinglReg(uint adr, uint data)
{
  return ILL_ADDR;
  //return 0;
}

uint writeMultReg(uint adr, uint Nreg)
{
  
  return ILL_FUNC;
  
  //return 0;
}

uint writeMaskReg(uint adr, uint mskAND, uint mskOR)
{
  return ILL_VAL;
  //return 0;
}




//
bool findID(void)
{
  while(InBgn!=InEnd)
   { 
     queryID = (*pUx).RdBufIn(InBgn);
     if(queryID==Dev_ID) {posa = COMask; return true;}
     if(queryID==PC_ID)  {posa = COMansw; return true;}
     (*pUx).next(&InBgn);
    }
  return false;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
//
uint readShort(void)
{ uint data;
  (*pUx).next(&InBgn); data = (uint)(*pUx).RdBufIn(InBgn)<<8;
  (*pUx).next(&InBgn); data += (*pUx).RdBufIn(InBgn);
  return data;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/



//
void writeShort(uint data)   { (*pUx).WrBufOut(data>>8);  (*pUx).WrBufOut((char)data); }
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/



//
uint RegsToBytes(uint adr,uint nBytes)
{
  if(nBytes>LastAdr-adr) nBytes = LastAdr-adr;
  if(nBytes>MaxNbytes)   nBytes = MaxNbytes;
  if(nBytes>(*pUx).GetBufSize()-6)   nBytes = (*pUx).GetBufSize()-6;
  return nBytes; 
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/